/*
 * TextDocumentDelegate.cpp  0.4.0 / Dec 04, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "TextDocumentDelegate.h"

#include "PrinterDelegate.h"
#include "SwingDelegate.h"
#include "QTextCharFormatAdapter.h"

// TextDocumentDelegate :: Protected Constructor. ------------------------------

/*!
 * \brief Constructs new TextDocumentDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing TextDocument object
 * \param document the Qt QTextDocument
 */
TextDocumentDelegate::TextDocumentDelegate(JNIEnv *env, jobject obj,
                                           QTextDocumentAdapter *document)
  : QObjectDelegate(env, obj, document)
{
  // empty constructor body
}

// TextDocumentDelegate :: Native Calls. ---------------------------------------

/*!
 * \brief Clears the text.
 *
 * \param env the JNIEnv pointer
 */
void TextDocumentDelegate::clearText(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(clearText, SWING_ENV_ARG)
  qTextDocument()->clear();
}

/*!
 * \brief Returns text of the document.
 *
 * \param env the JNIEnv pointer
 * 
 * \return text of the document
 */
jstring TextDocumentDelegate::getText(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT_RETURN(getText, jstring, SWING_ENV_ARG)
  return QStringAdapter::toJString(env, qTextDocument()->getText());
}

/*!
 * \brief Sets text of the document.
 *
 * \param env the JNIEnv pointer
 * \param text the text of the document
 */
void TextDocumentDelegate::setText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setText, SWING_ENV_ARG, JSTRING_ARG(text))
  qTextDocument()->setText(QStringAdapter(env, text));
}

/*!
 * \brief Appends text to the end of the document.
 *
 * \param env the JNIEnv pointer
 * \param text text the text to be appended
 */
void TextDocumentDelegate::appendText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  Q_ASSERT(text);
  SWING_REENTRANT(appendText, SWING_ENV_ARG, JSTRING_ARG(text))
  qTextDocument()->appendText(QStringAdapter(env, text));
}

/*!
 * \brief Returns \c true if undo operation is available.
 *
 * \param env the JNIEnv pointer
 * 
 * \return \c true if undo operation is available
 */
jboolean TextDocumentDelegate::isUndoAvailable(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT_RETURN(isUndoAvailable, jboolean, SWING_ENV_ARG)
  return qTextDocument()->isUndoAvailable();
}

/*!
 * \brief Returns \c true if redo operation is available.
 *
 * \param env the JNIEnv pointer
 * 
 * \return \c true if undo operation is available
 */
jboolean TextDocumentDelegate::isRedoAvailable(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT_RETURN(isRedoAvailable, jboolean, SWING_ENV_ARG)
  return qTextDocument()->isRedoAvailable();
}

/*!
 * \brief Undos last action.
 *
 * \param env the JNIEnv pointer
 */
void TextDocumentDelegate::undo(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(undo, SWING_ENV_ARG)
  qTextDocument()->undo();
}

/*!
 * \brief Redos last action.
 *
 * \param env the JNIEnv pointer
 */
void TextDocumentDelegate::redo(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(redo, SWING_ENV_ARG)
  qTextDocument()->redo();
}

/*!
 * \brief Sets whether or not the undo stack is enabled.
 *
 * \param env the JNIEnv pointer
 * \param enabled \c true if enabled
 */
void TextDocumentDelegate::setUndoRedoEnabled(JNIEnv *env, jboolean enabled)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setUndoRedoEnabled, SWING_ENV_ARG, JBOOLEAN_ARG(enabled))
  qTextDocument()->setUndoRedoEnabled(enabled);
}

/*!
 * \brief Sets undo/redo listening.
 *
 * \param env the JNIEnv pointer
 * \param listening \c true if listening
 */
void TextDocumentDelegate::setUndoRedoListening(JNIEnv *env, jboolean listening)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setUndoRedoListening, SWING_ENV_ARG,
                  JBOOLEAN_ARG(listening))
  if (listening) {
    connectAuto(qTextDocument(), SIGNAL(undoAvailable(bool)),
                SLOT(undoAvailableSlot(bool)));
    connectAuto(qTextDocument(), SIGNAL(redoAvailable(bool)),
                SLOT(redoAvailableSlot(bool)));
  } else {
    disconnect(qTextDocument(), SIGNAL(undoAvailable(bool)),
               SLOT(undoAvailableSlot(bool)));
    disconnect(qTextDocument(), SIGNAL(redoAvailable(bool)),
               SLOT(redoAvailableSlot(bool)));
  }
}

/*!
 * \brief Returns \c true if the document is modified.
 *
 * \param env the JNIEnv pointer
 * 
 * \return \c true if the document is modified
 */
jboolean TextDocumentDelegate::isModified(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT_RETURN(isModified, jboolean, SWING_ENV_ARG)
  return qTextDocument()->isModified();
}

/*!
 * \brief Sets whether or not the document is modified.
 *
 * \param env the JNIEnv pointer
 * \param modified \c true if modified
 */
void TextDocumentDelegate::setModified(JNIEnv *env, jboolean modified)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setModified, SWING_ENV_ARG, JBOOLEAN_ARG(modified))
  qTextDocument()->setModified(modified);
}

/*!
 * \brief Prints the document using the specified printer object.
 *
 * \param env the JNIEnv pointer
 * \param printer the Swing printer object
 */
void TextDocumentDelegate::print(JNIEnv *env, jobject printer)
{
  Q_ASSERT(env);
  Q_ASSERT(printer);
  SWING_REENTRANT(print, SWING_ENV_ARG, JOBJECT_ARG(printer))
  qTextDocument()->print(PrinterDelegate::toQPrinter(env, printer));
}

/*!
 * \brief Sets whether or not the document is using the highlighter.
 *
 * \param env the JNIEnv pointer
 * \param useHighlighter \c true if using
 */
void TextDocumentDelegate::setUseHighlighter(JNIEnv *env,
                                             jboolean useHighlighter)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setUseHighlighter, SWING_ENV_ARG,
                  JBOOLEAN_ARG(useHighlighter))
  qTextDocument()->setUseHighlighter(useHighlighter);
}

/*!
 * \brief Sets the character format for the specified text segment.
 *
 * \param env the JNIEnv pointer
 * \param start the start of the segment
 * \param length the length of the segment
 * \param format the format
 */
void TextDocumentDelegate::setFormat(JNIEnv *env, jint start, jint length,
                                     jobject format)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setFormat, SWING_ENV_ARG, JINT_ARG(start), JINT_ARG(length),
                  JOBJECT_ARG(format))
  qTextDocument()->setFormat(start, length, QTextCharFormatAdapter(format));
}

// TextDocumentDelegate :: Static Native Calls. --------------------------------

/*!
 * \brief Initializes TextDocumentDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the TextDocument class
 *
 * \exception FatalError if failed
 */
void TextDocumentDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT (!sm_delegateFID);
  if (!INIT_UFID(delegate, cls, "J") || !INIT_UMID(create, cls, "()J") ||
      !INIT_UMID(undoAvailable, cls, "(Z)V") || 
      !INIT_UMID(redoAvailable, cls, "(Z)V") || 
      !INIT_UMID(highlightBlock, cls, "(ILjava/lang/String;)V")) {
    FATAL_LOGGED_ERROR("TextDocumentDelegate initialization failed");
  }
}

// TextDocumentDelegate :: Native Callbacks. -----------------------------------

/*!
 * \brief Calls \c undoAvailable method of the TextDocument object.
 *
 * \param available \c true if available
 */
void TextDocumentDelegate::undoAvailable(jboolean available)
{
  jniObject()->callVoidMethod(sm_undoAvailableMID, available);
}

/*!
 * \brief Calls \c redoAvailable method of the TextDocument object.
 *
 * \param available \c true if available
 */
void TextDocumentDelegate::redoAvailable(jboolean available)
{
  jniObject()->callVoidMethod(sm_redoAvailableMID, available);
}

/*!
 * \brief Calls \c highlightDocument method of the TextDocument object.
 *
 * \param blockStart the block start
 * \param blockText the block text
 */
void TextDocumentDelegate::highlightBlock(jint blockStart, jstring blockText)
{
  jniObject()->callVoidMethod(sm_highlightBlockMID, blockStart, blockText);
}

// TextDocumentDelegate :: Overridden Member Functions. ------------------------

/*!
 * \inheritDoc
 */
void TextDocumentDelegate::destroy(JNIEnv *env)
{
  Q_UNUSED(env);
  qTextDocument()->setDestroying();
  if (SwingDelegate::isDisposed()) {
    delete this; // OK - referenced only from java
  } else {
    deleteLater();
  }
}

/*!
 * \brief Returns delegate pointer FID.
 *
 * \return delegate pointer FID 
 */
jfieldID TextDocumentDelegate::delegatePointerFID() const
{
  return sm_delegateFID;
}

// TextDocumentDelegate :: Public Static Member Function. ----------------------

/*!
 * \brief Returns QTextDocumentAdapter object of the specified Swing
 *        TextDocument object.
 *
 * \param env the JNIEnv pointer
 * \param document the Swing TextDocumen object
 * 
 * \return QTextDocumentAdapter object of the specified TextDocument object
 */
QTextDocumentAdapter *TextDocumentDelegate::toQDocument(JNIEnv *env,
                                                        jobject document)
{
  if (document) {
    return TEXT_DOCUMENT_CAST(
               JNIWrapper::getLongField(env, document,
                                        sm_delegateFID))->qTextDocument();
  }
  return 0;
}

// TextDocumentDelegate :: Protected Member Functions. -------------------------

/*!
 * \brief \c undoAvailable slot.
 *
 * \param available \c true if available
 */
void TextDocumentDelegate::undoAvailableSlot(bool available)
{
  undoAvailable(available);
}

/*!
 * \brief \c redAvailable slot.
 *
 * \param available \c true if available
 */
void TextDocumentDelegate::redoAvailableSlot(bool available)
{
  redoAvailable(available);
}

// TextDocumentDelegate :: Private Static Data Members. ------------------------

jfieldID TextDocumentDelegate::sm_delegateFID = 0;
jmethodID TextDocumentDelegate::sm_createMID = 0;
jmethodID TextDocumentDelegate::sm_undoAvailableMID = 0;
jmethodID TextDocumentDelegate::sm_redoAvailableMID = 0;
jmethodID TextDocumentDelegate::sm_highlightBlockMID = 0;
